package seabattle;

import seabattle.field.BattleField;
import seabattle.field.Cell;
import seabattle.field.FieldEditable;
import seabattle.field.Message;
import seabattle.movements.ComputerMovement;
import seabattle.movements.Movement;
import seabattle.ship.Coordinates;
import seabattle.ship.RandomShipGenerator;
import seabattle.ship.ShipsGenerator;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
//import java.net.URL;
import java.util.LinkedList;

public class AppletEngine extends JComponent {
	private static final long serialVersionUID = 1L;
	private final BattleField playerField = new BattleField();
	private final BattleField computerField = new BattleField();
	private final LinkedList<Rectangle2D> playerSquares = new LinkedList<Rectangle2D>();
	private final LinkedList<Rectangle2D> computerSquares = new LinkedList<Rectangle2D>();
	private final ShipsGenerator shipGenerator = new ShipsGenerator(
			new RandomShipGenerator());
	private final Movement computer = new ComputerMovement();
	private final int playerLeftX = 30;
	private final int computerLeftX = 400;
	private Graphics2D g2;
	private boolean play;
	Image background;

	public AppletEngine() {
		shipGenerator.generateOn(playerField);
		shipGenerator.generateOn(computerField);
		computerField.setVisible(false);
		sketch(playerSquares, playerLeftX);
		sketch(computerSquares, computerLeftX);
		setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		// URL sourceURL = getClass().getResource("seabackground.jpg");
		// background = Toolkit.getDefaultToolkit().getImage(sourceURL);
		addMouseListener(new MouseHandler());
		play = true;
	}

	public void paintComponent(Graphics g) {
		g2 = (Graphics2D) g;
		// g2.drawImage(background, 0, 0, this);
		reflect(playerField, playerSquares);
		reflect(computerField, computerSquares);
	}

	private void sketch(LinkedList<Rectangle2D> list, int offset) {
		for (int row = 0; row < BattleField.SIZE; row++) {
			for (int column = 0; column < BattleField.SIZE; column++) {
				final int SIDE_SIZE = 25;
				double x = offset + column * SIDE_SIZE + column * 2;
				final int topY = 30;
				double y = topY + row * SIDE_SIZE + row * 2;
				list.add(new Rectangle2D.Double(x, y, SIDE_SIZE, SIDE_SIZE));
			}
		}
	}

	private void reflect(FieldEditable field, LinkedList<Rectangle2D> list) {
		for (int row = 0; row < BattleField.SIZE; row++) {
			for (int column = 0; column < BattleField.SIZE; column++) {
				Rectangle2D rect = list.get(row * BattleField.SIZE + column);
				Color color = cellColor(field.getCell(column, row),
						field.getVisible());
				g2.setPaint(color);
				// new
				// GradientPaint(30,30,Color.darkGray,130,130,Color.LIGHT_GRAY,true)
				g2.fill(rect);
				g2.setPaint(Color.BLACK);
				g2.draw(rect);
			}
		}
	}

	private Color cellColor(Cell cell, boolean showShips) {
		switch (cell) {
		case EMPTY:
			return Color.LIGHT_GRAY;
		case SHIP:
			if (showShips) {
				return new Color(0x4d, 0x87, 0xd3); // Blue;
			} else {
				return Color.LIGHT_GRAY;
			}
		case SHOT:
			return Color.DARK_GRAY;
		case HIT:
			return new Color(0xff, 0x72, 0x00); // Orange;
		}
		return Color.WHITE;
	}

	private void gameOver() {
		play = false;
		repaint();
	}

	class MouseHandler extends MouseAdapter {

		public Coordinates find(Point2D p) {
			for (int index = 0; index < computerSquares.size(); index++) {
				if (computerSquares.get(index).contains(p)) {
					int y = index / 10;
					int x = index - y * 10;
					return new Coordinates(x, y);
				}
			}
			return null;
		}

		public void mousePressed(MouseEvent event) {
			final int MAX_LOOP_COUNT = 10000;
			if (!play) {
				return;
			}
			Coordinates current = find(event.getPoint());
			if (current == null) {
				return;
			}
			Message result = computerField.catchingShot(current);
			repaint();
			if (result == Message.HIT) {
				if (!computerField.checkAliveShips()) {
					gameOver();
				}
				return;
			} else if (result == Message.AGAIN) {
				return;
			} else if (result == Message.MISS) {
				// do nothing
			}
			int count = 0;
			do {
				Coordinates coordinates = computer.getShot();
				result = playerField.catchingShot(coordinates);
				if (result == Message.HIT) {
					if (!playerField.checkAliveShips()) {
						gameOver();
						break;
					}
				}
				if (result == Message.MISS) {
					break;
				}
				count++;
			} while (count < MAX_LOOP_COUNT);
		}
	}

}